import pygame
import sys
import StringIO


#This console will automatically resize and reposition to the correct area in the screen depending on the window size.
#It will execute any command given and output the results.

#To include this console with your code, simply include the following somewhere in your code:
# from console import *

#After your pygame screen surface has been set up, call:
# command.setup( ~your python main screen surface here~ )

#To show the console, merely call
# command.showSurface()
#The function will return 0 if a quit event is recieved, 1 otherwise.

#CONSOLE INSTRUCTIONS:
#Typing in a command will result in the command being executed. Any print statements will be captured and outputted to the console window.
#Prefixing a command with ? (IE: '?some_variable == 5') will result in the command being sent to eval() and the value returned.
#Strange errors may be the result of using eval on something that eval doesnt play nice with. Try it without the ?
#If the ? prefix does not work, and you really need the data returned, try using 'print my_expression_here' instead to circumvent the issue.

class console:
	def __init__(self):
		self.command = ""
		self.lastcommand = ""
		self.out = ["","","","","","","","","","","pyConsole programmed 2007, Michael Pratt", "Enter any python code to execute without a return value. Prefix with a ? to return the eval() value."]
		
	def setup(self, screen, height = 200, font = None):
		self.screen = screen
		self.height = height
		if font is None:
			font = pygame.font.Font(None, 16)
		self.font = font
		
	def addLine(self, line):
		self.out.pop(0)
		self.out.append(line)

	def showConsole(self, glob, loc):
		print "Entering console..."
		
		globals().update(glob)
		locals().update(loc)
		
		screensize = self.screen.get_size()
		
		#to allow the transparency, we need to make a copy of what the screen looks like.
		screen2 = self.screen.copy()
		screen2.set_alpha(50)
		
		# make the console background
		consolebg = pygame.Surface((screensize[0], 200)).convert()
		consolebg.fill((0,0,0))
		consolebg.blit(screen2, (0, self.height - screensize[1]))
		console = pygame.Surface(consolebg.get_size()).convert()
		
		inconsole = 1
		
		play = 1
		
		# console key aquire loop
		while inconsole:
			for event in pygame.event.get():
				if event.type == QUIT:
					play = 0
					inconsole = 0
				if event.type == KEYDOWN:
					if (event.key == K_ESCAPE or event.key == K_BACKQUOTE):
						inconsole = 0
					elif event.key == K_BACKSPACE:
						self.command = self.command[:-1]
					elif event.key == K_UP:
						self.command = self.lastcommand
					elif event.key == K_RETURN:
						print "Attempting execute: " + self.command
						self.lastcommand = self.command
						
						# create file-like string to capture output
						codeOut = StringIO.StringIO()
						 
						 
						# capture output and errors
						sys.stdout = codeOut
						 
						executed = 0
						try:
							if self.command[0] == '?':
								print self.command[1:] + ": " + str(eval(self.command[1:]))
							else:
								exec(self.command)
								executed = 1
								
						except Exception, reason:
							print "Error executing command: " + self.command
							print reason
						
						# restore stdout and stderr
						sys.stdout = sys.__stdout__
						sys.stderr = sys.__stderr__
						
						s = codeOut.getvalue()
						print s
						
						linelist = s.split('\n')
						
						if executed == 1:
							if len(linelist) == 1:
								self.addLine("Executed: " + self.command)
							else:
								self.addLine(self.command + ":")
						
						for item in linelist:
							if item != "":
								self.addLine(item)
							
						codeOut.close()
						
						self.command = ""
					else :
						self.command += event.unicode
						
			commandline = "> " + self.command + "_"
			
			#throw together the console surface
			console.blit(consolebg, (0,0))
			
			y = 0
			
			surf = self.font.render(commandline, 1, (255, 255, 255))
			console.blit(surf, (0, 186))
			
			for item in self.out:
				surf = self.font.render(item, 1, (255, 255, 255))
				console.blit(surf, (0, y))
				y += 16
				
			#overlay BG...
			self.screen.blit(console, (0, screensize[1]-self.height))

			pygame.display.update()
			# no need to maintain framerate
		return play

command = console()

try:
	import pygui
	from pygui import *
	command.addLine("pyConsole starting with pieguy imported for your convenience.")
except Exception, reason:
	command.addLine("No pieguy detected, starting console without it..")
